home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / viewers / polyview / polyvw31.lha / Polyview3.1 / new / pvdtm.c < prev    next >
C/C++ Source or Header  |  1993-08-13  |  31KB  |  1,011 lines

  1. /*****************************************************************************
  2.  * NCSA Polyview 3.1                                                         *
  3.  *                                                                           *
  4.  * Version 3.1 changes and additions by Gilles Bourhis.                      *
  5.  * Version 3 changes and additions by Marc Andreessen.                       *
  6.  * Version 2 by Brian Calvert.                                               *
  7.  *                                                                           *
  8.  * Software Development Group                                                *
  9.  * National Center for Supercomputing Applications                           *
  10.  * University of Illinois at Urbana-Champaign                                *
  11.  *                                                                           *
  12.  * This is BETA release software.  As such it may contain software bugs and  *
  13.  * exhibit inconsistencies.                                                  *
  14.  *                                                                           *
  15.  * Please send bug reports to polyview@ncsa.uiuc.edu.                        *
  16.  *                                                                           *
  17.  * Copyright (c) 1992 The Board of Trustees of the University of Illinois.   *
  18.  *                                                                           *
  19.  * Permission to use, copy, and modify this software and its                 *
  20.  * documentation for educational, research, and non-profit purposes is       *
  21.  * hereby granted, provided that the above copyright notice, the original    *
  22.  * authors names, and this permission notice appear in all such copies.      *
  23.  * Any distribution of this software requires the explicit and written       *
  24.  * authorization of the authors.                                             *
  25.  *                                                                           *
  26.  * The University of Illinois makes no representations about the             *
  27.  * suitability of this software for any purpose.  It is provided "as is"     *
  28.  * without warranty of any kind.                                             *
  29.  *****************************************************************************/
  30.  
  31. /* $Id: pvdtm.c,v 1.3 93/08/13 13:55:18 gbourhis Exp $ */
  32.  
  33. #ifdef RCSLOG
  34. $Log:    pvdtm.c,v $
  35.  * Revision 1.3  93/08/13  13:55:18  gbourhis
  36.  * changes in COMreceive_vdata() and _send_vdatas_in_vgroup().
  37.  * 
  38.  * Revision 1.2  93/07/13  16:35:46  gbourhis
  39.  * add COMreceive_srv() to handle connect SRV message.
  40.  * 
  41.  * Revision 1.1  92/09/18  10:55:26  marca
  42.  * Initial revision
  43.  * 
  44. #endif
  45.  
  46. #include "pv.h"
  47. #include <net.h>
  48. #include <netdata.h>
  49. #include <dtm.h>
  50. #include <srv.h>
  51. #include <sdl.h>
  52.  
  53. /*
  54.   This file implements support for Vsets via DTM.  DTM will only deal
  55.   with Vdata's; each Vdata will come with a ``magic path'' which will
  56.   uniquely identify it within a Vset (aka Vgroup tree).  What makes the
  57.   a Vdata's path ``magic'' is the fact that it implicitly specifies the
  58.   structure of the Vset (which is never sent, per se, via DTM); thus,
  59.   when we receive a new Vdata, we create whatever Vgroups are necessary
  60.   to place the new Vdata in its proper position.
  61.   
  62.   Calling Interfaces:
  63.   
  64.   External routines have the prefix COM, for communication.
  65.   
  66.   COMsend_vset
  67.   COMdtm_in
  68.   COMdtm_out
  69.   COMpoll
  70.   
  71.   To Do:
  72.   
  73.   Data sharing is greatly lacking.  We should be considering each Vset
  74.   to be a DAG, not a tree.
  75. */
  76.  
  77. /* Creation of an input port implies done_init and done_register
  78.    as well as done_inport.  Creation of an output port implies 
  79.    all of these (since an input port is always created prior to
  80.    creating an output port). */
  81.  
  82. /* Note that this design specifically excludes the possibility
  83.    of either multiple input or output ports, even in separate windows
  84.    of the application.  This bears thought. */
  85.  
  86. static int done_init = 0;       /* called NetInit?? */
  87. static int done_register = 0;   /* called NetRegisterModule?? */
  88. static int done_outport = 0;    /* called NetCreateOutPort?? */
  89. static int done_inport = 0;     /* called NetCreateInPort?? */
  90.  
  91.  
  92. /* ------------------------------------------------------------------------ */
  93. /* --------------------------- UTILITY ROUTINES --------------------------- */
  94. /* ------------------------------------------------------------------------ */
  95.  
  96. static void _dump_magic_path (VdataPathElement *magic_path, int depth)
  97. {
  98.   int i;
  99.  
  100.   fprintf (stdout, "  [_dump_magic_path] depth is %d\n", depth);
  101.   for (i = 0; i < (depth + 1); i++)
  102.     fprintf (stdout, "  [_dump_magic_path] %d> %d %s\n", i, 
  103.              magic_path[i].nodeID,
  104.              magic_path[i].nodeName);
  105.   fprintf (stdout, "  [_dump_magic_path] ************ DONE\n");
  106.   fflush (stdout);
  107.  
  108.   return;
  109. }
  110.  
  111.  
  112. /* ------------------------------------------------------------------------ */
  113. /* ------------------------------- RECEIVE -------------------------------- */
  114. /* ------------------------------------------------------------------------ */
  115.  
  116. /* This routine is the callback for receiving a new vdata
  117.    from the NET module. */
  118. static void COMreceive_vdata (Data *data, caddr_t state_addr)
  119. {
  120.   /* The header vgroup for this vset. */
  121.   Vgroup_t *vset;
  122.   
  123.   /* The vgroup we're currently working on, and its child. */
  124.   Vgroup_t *vptr, *vptr_child;
  125.  
  126.   /* Depth in the path so far. */
  127.   int depth;
  128.  
  129.   /* The new vdata being received. */
  130.   Vdata_t *vdata;
  131.   int vdata_id       = data->nodeID;
  132.   int vdata_type;                        /* This is NOT data->dost. */
  133.   char *vdata_name   = data->nodeName;
  134.   char *vdata_fields = data->fields;
  135.   char *vdata_data   = data->data;
  136.  
  137.   /* The magic path for this vdata. */
  138.   VdataPathElement *magic_path = *(data->magicPath);
  139.   int path_length              = data->pathLength;
  140.  
  141.   /* The state and window structs. */
  142.   state_t *state = (state_t *)state_addr;
  143.   window_t *win;  /* Grab the window out of state's list. */
  144.  
  145.   /* Reset flag. */
  146.   int reset;
  147.  
  148.   /* ---------------------------------------------------------------------- */
  149.   
  150.   /* Sanity-check the net module. */
  151.   if (data->dot != DOT_VData)
  152.     {
  153.       fprintf (stderr, 
  154.                "[COMreceive_vdata] Object other than Vdata rejected.\n");
  155.       fflush (stderr);
  156.       return;
  157.     }
  158.   if (data->dost != DOST_Float && data->dost != DOST_Int32)
  159.     {
  160.       fprintf 
  161.         (stderr, 
  162.          "[COMreceive_vdata] Polyview only supports floats and ints!\n");
  163.       fflush (stderr);
  164.       return;
  165.     }
  166.  
  167.   /* We should probably support doubles as well, and convert on
  168.      the fly. */
  169.  
  170.   /* ---------------------------------------------------------------------- */
  171.  
  172.   /* Figure out which window we're dealing with. */
  173.   win = NULL;
  174.   FOR_ALL_WINDOWS(state, win)
  175.     {
  176.       files_t *file;
  177.       file = WIN_SOURCE(win);
  178.       if ((file != NULL) && (file->type == DTMPORT))
  179.         break;
  180.     }
  181.  
  182.   /* Can't find a window to receive data into. */
  183.   if (win == NULL)
  184.     {
  185.       if ((win = GetActiveWindow(state)) == NULL)
  186.     return;
  187.       data_dtm_explicit(state, win, "dtm");
  188.     }
  189.   else
  190.     win_activate(state, win);
  191.       
  192. #ifdef PRIVATE_SUPPORT
  193.   /* Check for privacy enabled in that window. */
  194.   if (win->private)
  195.     return;
  196. #endif
  197.  
  198.   stprintf (state, "Receiving vdata %s via DTM...\n", vdata_name);  
  199.  
  200.   /* The first element of the magic path identifies the vset 
  201.      to which this vdata belongs.  Go try to find it. */
  202.   vptr = find_vgroup (state, WIN_SOURCE(win), magic_path[0].nodeName);
  203.  
  204.   /* If it exists, we now have a pointer to it.  If not,
  205.      create a new vset. */
  206.   reset = FALSE;
  207.   if (vptr == NULL)
  208.     {
  209.       vptr = add_vgroup (state, magic_path[0].nodeID, magic_path[0].nodeName,
  210.                          WIN_SOURCE(win)->groups);
  211.       vptr->children_read = TRUE;
  212.       reset = TRUE;
  213.     }
  214.  
  215.   /* Keep this vset around for reference. */
  216.   vset = vptr;
  217.  
  218.   /* ---------------------------------------------------------------------- */
  219.  
  220.   /* path_length is the number of elements in the array magic_path.
  221.      In other words, magic_path is defined for [0..path_length-1]. */
  222.   
  223.   /* depth is how deep we are in the path so far.  Since we've already
  224.      dealt with the first element of magic_path, depth = 1 here. */
  225.   depth = 1;
  226.   
  227.   /* We will have reached the parent vgroup when we have found
  228.      the vgroup corresponding to magic_path[path_length-1].
  229.      As long as we have not reached that point, keep iterating. */
  230.   while (depth < (path_length - 1))
  231.     {
  232.       /* Try to find the child of vptr with this name/id. */
  233.       vptr_child = GetVgroupInVgroup (state, vptr, magic_path[depth].nodeName);
  234.  
  235.       /* If child doesn't exist, make a child with vptr as parent. */
  236.       if (vptr_child == NULL)
  237.         {
  238.           vptr_child = add_vgroup
  239.             (state, magic_path[depth].nodeID, magic_path[depth].nodeName, 
  240.              vptr);
  241.           vptr_child->children_read = TRUE;
  242.         }
  243.       
  244.       /* Make the child the new parent. */
  245.       vptr = vptr_child;
  246.       /* Go a level deeper. */
  247.       depth++;
  248.     }
  249.  
  250.   /* ---------------------------------------------------------------------- */
  251.  
  252.   /* When we hit this point, we assume vptr is the parent vgroup for
  253.      this vdata. */
  254.  
  255.   /* Figure out what type of data we're dealing with. */
  256.   switch (data->dost)
  257.     {
  258.     case DOST_Float:
  259.       vdata_type = PVFLOAT;
  260.       break;
  261.     case DOST_Int32:
  262.       vdata_type = PVINTEGER;
  263.       break;
  264.     default:
  265.       stprintf (state, "[COMreceive_vdata] ERROR: Unknown type %d.\n",
  266.                 data->dost);
  267.       break;
  268.     }
  269.   
  270.   /* Go find the vdata in vptr. */
  271.   vdata = get_vdata_in_vgroup (state, vptr, vdata_name);
  272.  
  273.   if (vdata == NULL)
  274.     {
  275.       /* If a vdata didn't already exist, make one. */
  276.       vdata = add_vdata (state, vdata_id, vdata_name, vptr);
  277.  
  278.       /* Set the vdata parts. */
  279.       /* vdata->fields is an array */
  280.       strcpy (vdata->fields, vdata_fields);
  281.       vdata->stats_read = FALSE;
  282.       vdata->data = vdata_data;
  283.       vdata->in_memory = TRUE;
  284.  
  285.       /* Set the stats parts. */
  286.       vdata->stats[0].type = vdata_type;
  287.       /* rank is always 2, dim[0] = number of elements per record
  288.          and dim[1] = number of records */
  289.       vdata->stats[0].rec_size = data->dim[0];
  290.       vdata->stats[0].rec_count = data->dim[1];
  291.  
  292.       calc_stats (state, vdata);
  293.     }
  294.   else
  295.     {
  296.       /* If the vdata already exists (less likely), then just
  297.          replace its data. */
  298.       /* replace_vdata_contents (state, vdata_data, ...); */
  299.       /* For now, punt. */
  300.       fprintf (stdout, "[COMreceive_vdata] Vdata already exists!\n");
  301.       fflush (stdout);
  302.     }
  303.  
  304.   stprintf (state, "Receiving vdata %s via DTM... done\n", vdata_name);
  305.  
  306. #if 0
  307.   if (vdata_type == PVINTEGER)
  308.     {
  309.       int i;
  310.       PRT (("FOR VDATA %s\n", vdata_name));
  311.       PRT (("  size %d count %d\n", 
  312.             vdata->stats[0].rec_size, vdata->stats[0].rec_count));
  313.       for (i = 0; 
  314.            i < vdata->stats[0].rec_size * vdata->stats[0].rec_count; i++)
  315.         {
  316.           PRT (("%d ", ((int *)(vdata->data))[i]));
  317.         }
  318.     }
  319. #endif
  320.   
  321.   /* Do resets of time, info, whatever. */
  322.   /* This is probably a bad bad idea for each incoming vdata... */
  323.   WIN_GROUP(win) = set_vgroup (state, WIN_SOURCE(win), WIN_GROUPNAME(win));
  324.  
  325.   /* That's all, folks. */
  326.   return;
  327. }
  328.  
  329.  
  330. /* ------------------------------------------------------------------------ */
  331. /* --------------------------------- SEND --------------------------------- */
  332. /* ------------------------------------------------------------------------ */
  333.  
  334. /* ------------------------ _send_vdatas_in_vgroup ------------------------ */
  335. static void  _send_vdatas_in_vgroup (Vgroup_t *vptr, 
  336.                                      VdataPathElement *magic_path,
  337.                                      int depth)
  338. {
  339.   /* We receive a vgroup, the current magic path, and depth, which
  340.      is the depth of the vgroup in the vset.  The length of the magic
  341.      path is thus depth + 1. */
  342.  
  343.   /* Vdata pointer. */
  344.   Vdata_t *vdptr;
  345.  
  346.   /* Type to send, DOST_Float or DOST_Int32. */
  347.   int type;
  348.  
  349.   /* Return code from send. */
  350.   int rc;
  351.  
  352.   if (!done_outport)
  353.     {
  354.       stprintf (gstate, "ERROR trying to send with no outport\n");
  355.       return;
  356.     }
  357.  
  358.   /* We start with the first child. */
  359.   vdptr = vptr->vdatas;
  360.   
  361.   /* In this vdata:
  362.      We have array stats[MAXDATADIMS] == stats[4].
  363.      MAXDATADIMS = maximum width of a vdata.
  364.      Each stats has:
  365.        type (PVINTEGER or PVFLOAT)
  366.        rec_count (number of records)
  367.        rec_size (number of elements per record).
  368.      Refer to stats[0] only.  That's just the way it works. */
  369.   
  370.   /* While we have child vdatas left to send, send 'em. */
  371.   for (; vdptr != NULL; vdptr = vdptr->sibling)
  372.     {
  373.       if (! vdptr->in_memory)    /* skip it if not in memory */
  374.     continue;
  375.  
  376.       switch (vdptr->stats[0].type)
  377.         {
  378.         case PVINTEGER:
  379.           type = DOST_Int32;
  380.           break;
  381.         case PVFLOAT:
  382.           type = DOST_Float;
  383.           break;
  384.         default:
  385.           fprintf (stderr, 
  386.                    "[_send_vdatas_in_vgroup] OOPS Polyview type of %d\n",
  387.                    vdptr->stats[0].type);
  388.           fflush (stderr);
  389.           return;
  390.         }
  391.       
  392.       rc =
  393.         NetSendVData
  394.           (NULL,                        /* netport, or NULL for all */
  395.            vdptr->name,                 /* label, duplicate of nodeName */
  396.            &magic_path,                 /* magic path */
  397.            depth + 1,                   /* magic path length */
  398.            vdptr->id,                   /* node ID */
  399.            vdptr->name,                 /* node name */
  400.            " ", /* vdptr->fields, */    /* fields in vdata */
  401.            vdptr->stats[0].rec_count,   /* number of records */
  402.            vdptr->stats[0].rec_size,    /* number of elements */
  403.            type,                        /* type */
  404.            vdptr->data,                 /* the data itself */
  405.            FALSE,                       /* copy before returning */
  406.            FALSE,                       /* distribute internally */
  407.            NULL                         /* if ^^ is TRUE, this is our name */
  408.            );
  409.  
  410.     }
  411.   
  412.   /* That's all, folks. */
  413.   return;
  414. }
  415.  
  416. /* --------------------------- _traverse_vgroup --------------------------- */
  417.  
  418. static void _traverse_vgroup (Vgroup_t *vptr, VdataPathElement *magic_path,
  419.                               int depth)
  420. {
  421.   /* We receive an arbitrary vgroup, a partially constructed magic_path,
  422.      and an arbitrary depth in a vset. */
  423.   char *name;
  424.   
  425.   /* Load this element of the magic path. */
  426.   name = (char *)PVMALLOC (strlen (vptr->name) + 1);
  427.   if (name == NULL)
  428.     {
  429.       fprintf (stderr, "YOW! PVMALLOC NULL in _traverse_vgroup.\n");
  430.       fflush (stderr);
  431.     }
  432.   
  433.   magic_path[depth].nodeName = 
  434.     strcpy ((char *)PVMALLOC (strlen (vptr->name) + 1), vptr->name);
  435.   magic_path[depth].nodeID = vptr->id;
  436.   
  437.   /* Check for vdatas. */
  438.   if (vptr->vdatas != NULL)
  439.     _send_vdatas_in_vgroup (vptr, magic_path, depth);
  440.   
  441.   /* Check for child vgroup; if there's more than one, the sibling
  442.      pointer will handle the rest. */
  443.   if (vptr->groups != NULL)
  444.     _traverse_vgroup (vptr->groups, magic_path, depth + 1);
  445.   
  446.   /* Check for sibling vgroup. */
  447.   if (vptr->sibling != NULL)
  448.     _traverse_vgroup (vptr->sibling, magic_path, depth);
  449.   
  450.   /* That's all, folks. */
  451.   return;
  452. }
  453.  
  454.  
  455. /* Does this make sense? */
  456. #define MAX_MAGIC_PATH_LENGTH 20
  457.  
  458. /* ----------------------------- COMsend_vset ----------------------------- */
  459.  
  460. /* This routine is called from Polyview and broadcasts an entire
  461.    Vset.  This is all Polyview will probably do by itself, since it
  462.    doesn't actually create data. */
  463. void COMsend_vset (state_t *state, Vgroup_t *vset)
  464. {
  465.   /* The current vgroup. */
  466.   Vgroup_t *vptr;
  467.   
  468.   /* The current path. */
  469.   VdataPathElement *magic_path;
  470.   
  471.   /* The current depth in the path.  0 means we're at the base. */
  472.   int depth;
  473.   
  474.   if (!done_outport)
  475.     {
  476.       fprintf (stderr, "ERROR trying to send vset with no outport\n");
  477.       fflush (stderr);
  478.       return;
  479.     }
  480.   
  481.   /* We want to do a depth-first traversal of vset and
  482.      its children.  Currently we pretend we're dealing with
  483.      a tree, even though it's really a DAG.  Tough shit. */
  484.   
  485.   /* A traversal involves tracking the current location
  486.      in the tree via magic_path. */
  487.   magic_path = 
  488.     (VdataPathElement *)PVMALLOC 
  489.       (MAX_MAGIC_PATH_LENGTH * sizeof (VdataPathElement));
  490.   
  491.   /* We're currently pointing at the head of the tree. */
  492.   depth = 0;
  493.   vptr = vset;
  494.   
  495.   /* Traverse the tree.  At any point in here, magic_path_length
  496.      will be depth + 1; this is important. */
  497.   _traverse_vgroup (vptr, magic_path, depth);
  498.   
  499.   /* That's all, folks. */
  500.   return;
  501. }
  502.  
  503.  
  504. /* ------------------------------------------------------------------------ */
  505. /* ---------------------------- COMreceive_sdl ---------------------------- */
  506. /* ------------------------------------------------------------------------ */
  507.  
  508. #define MAX_VERTICES 10000
  509.  
  510. /* Accept three floating-point values and build an index into the
  511.    Polyview RGB colormap. */
  512. #define    RGB_TO_CMAP(r,g,b) \
  513.   ((((int)(b*3.0))<<6) | (((int)(g*7.0))<<3) | (((int)(r*7.0))))
  514. #define    PVREALLOC(p,n,t,r) \
  515.   ((p) ? (t (*) r)realloc(p,n*sizeof(t r)) : (t (*) r)calloc(n, sizeof(t r)))
  516.  
  517. /* Given a vgroup, read vertices into vdatas named "pcoord"
  518.    and "color". */
  519. static int ReadVertexList (state_t *state, Vgroup_t *vg, Data *data)
  520. {
  521.   int    i, vcount;
  522.   float    r, g, b;
  523.   float    mag;
  524.   int    *colorp;
  525.   float    (*pcoord)[DIMS];
  526.   int    size, count;
  527.   Vdata_t *color_v, *pcoord_v;
  528.   struct DTM_TRIPLET *primbuf;
  529.   
  530.   /* Find the existing vdatas in the group, if possible. */
  531.   /* If they don't exist, create them. */
  532.   if ((pcoord_v = get_vdata_in_vgroup(state, vg, "pcoord")) == NULL) 
  533.     {
  534.       pcoord_v = add_vdata(state, -1, "pcoord", vg);
  535.       pcoord_v->data = NULL;
  536.       pcoord_v->in_memory = TRUE;
  537.       size = pcoord_v->stats[0].rec_count = 0;
  538.       pcoord_v->stats[0].rec_size = 3;
  539.       pcoord_v->stats[0].type = PVFLOAT;
  540.     }
  541.   else 
  542.     size = pcoord_v->stats[0].rec_count;
  543.   
  544.   if ((color_v = get_vdata_in_vgroup(state, vg, "color")) == NULL) 
  545.     {
  546.       color_v = add_vdata(state, -1, "color", vg);
  547.       color_v->data = NULL;
  548.       color_v->in_memory = TRUE;
  549.       color_v->stats[0].rec_count = 0;
  550.       color_v->stats[0].rec_size = 1;
  551.       color_v->stats[0].type = PVINTEGER;
  552.     }
  553.   
  554.   if (pcoord_v->stats[0].rec_count != color_v->stats[0].rec_count) 
  555.     {
  556.       stprintf(gstate, "SYSTEM ERROR: pcoord and color sizes don't match!\n");
  557.       return ST_ERROR;
  558.     }
  559.     
  560.   /* Allocate space for the color and pcoord data. */
  561.   colorp = (int *) color_v->data;
  562.   pcoord = (float (*)[DIMS]) pcoord_v->data;
  563.   count = 0;
  564.     
  565.   /* Now data->dim[1] = number of DTM_TRIPLETS.  This will be vcount. */
  566.   vcount = data->dim[1];
  567.  
  568.   /* primbuf is created now as a cast from the character data we
  569.      receive from the net module. */
  570.   primbuf = (struct DTM_TRIPLET *)(data->data);
  571.   
  572.   /* Initially size is 0 (meaning we get a realloc first thing).
  573.      i will range from 0 to the number of primitives (coords
  574.      plus colors) in the dataset. */
  575.  
  576.   /* For each triplet, read it.  For each position, increment count
  577.      of coords.  When we max out the current allocation of coords
  578.      (three floats and one int in pcoord and colorp respectively)
  579.      allocate more space. */
  580.   for (i = 0; i < vcount; i++)
  581.     {
  582.       if (count == size) 
  583.         {
  584.           /* We've maxed out current storage; go get more. */
  585.           size += MAX_VERTICES;
  586.           colorp = PVREALLOC(colorp, size, int, );
  587.           pcoord = PVREALLOC(pcoord, size, float, [DIMS]);
  588.         }
  589.       
  590.       if (primbuf[i].tag == SDLposition)  
  591.         {
  592.           /* Add the current color and position to their vdatas
  593.              and increment the count of coords. */
  594.           colorp[count] = RGB_TO_CMAP(r, g, b);
  595.           pcoord[count][X] = primbuf[i].x;
  596.           pcoord[count][Y] = primbuf[i].y;
  597.           pcoord[count][Z] = primbuf[i].z;
  598.  
  599.           count++;
  600.         }
  601.       
  602.       else if (primbuf[i].tag == SDLcolor)  
  603.         {
  604.           /* All we do is store this color for use with the next
  605.              position. */
  606.           r = primbuf[i].x;
  607.           g = primbuf[i].y;
  608.           b = primbuf[i].z;
  609.         }
  610.       
  611.       else if (primbuf[i].tag == SDLnormal) 
  612.         {
  613.           /* Old normal code taken out... Polyview doesn't do
  614.              normals yet, but it will derive them on a polygon
  615.              basis in the drawing routines. */
  616.         }
  617.     }
  618.  
  619.   /* Trim off the extra memory from the arrays. */
  620.   colorp = PVREALLOC(colorp, count, int, );
  621.   pcoord = PVREALLOC(pcoord, count, float, [DIMS]);
  622.   
  623.   /* Store the data as vdatas, deleting any existing data. */
  624.   /* Update any instances of the vdata in the diplay tree. */
  625.   color_v->data = (char *)colorp;
  626.   pcoord_v->data = (char *)pcoord;
  627.   pcoord_v->stats[0].rec_count = color_v->stats[0].rec_count = count;
  628.  
  629.   calc_stats(state, pcoord_v);
  630.   calc_stats(state, color_v);
  631.   
  632.   return count;
  633. }
  634.  
  635.  
  636. /* Given a vgroup, width of each connectivity spec (3=tri, etc),
  637.    and number of vertices, build a connectivity vdata in this
  638.    vgroup. */
  639. static void BuildConnectList (state_t *state, Vgroup_t *vg, 
  640.                               int width, int vertices)
  641. {
  642.   Vdata_t *connect_v;
  643.   int *connect = NULL;
  644.   int *c;
  645.   int i;
  646.   char plist[MAXNAMELEN];
  647.   int length;
  648.   int count;
  649.  
  650.   /* Calculate the number of polygons in the list. */
  651.   length = vertices / width;
  652.   
  653.   /* Get any existing connectivity data.  Otherwise, create it. */
  654.   sprintf(plist, "plist%d", width);
  655.   if ((connect_v = get_vdata_in_vgroup(state, vg, "plist*")) == NULL) 
  656.     {
  657.       connect_v = add_vdata(state, -1, plist, vg);
  658.       connect_v->data = NULL;
  659.       connect_v->in_memory = TRUE;
  660.       connect_v->stats[0].rec_count = 0;
  661.       connect_v->stats[0].rec_size = 0;
  662.       connect_v->stats[0].type = PVINTEGER;
  663.     }
  664.   count = length * width;
  665.  
  666.   if ((length != connect_v->stats[0].rec_count) ||
  667.       (width != connect_v->stats[0].rec_size)) 
  668.     {
  669.       connect_v->data = (char *) PVREALLOC(connect, count, int, );
  670.       strcpy(VDA_NAME(connect_v), plist);
  671.     }
  672.   connect_v->stats[0].rec_count = length;
  673.   connect_v->stats[0].rec_size = width;
  674.   connect = (int *) connect_v->data;
  675.   
  676.   /* Fill the connectivity list with the appropriate connections. */
  677.   for (i = 1, c = connect; i <= count; c++, i++)
  678.     *c = i;
  679.   
  680.   /* Store the list as a vdata, deleting any existing data. */
  681.   /* Update any instances of the vdata in the diplay tree. */
  682.   calc_stats(state, connect_v);
  683.   
  684.   return;
  685. }
  686.  
  687.  
  688. static void COMreceive_sdl (Data *data, caddr_t state_addr)
  689. {
  690.   state_t      *state = (state_t *)state_addr;
  691.   window_t     *win;
  692.   char        header[DTM_MAX_HEADER];
  693.   char        title[MAXNAMELEN];
  694.   char           *path;
  695.   SDLprim_t    prim;
  696.   int        size, count;
  697.   Vgroup_t     *vg;
  698.   int        reset;
  699.  
  700.   /* Figure out which window we're dealing with. */
  701.   win = NULL;
  702.   FOR_ALL_WINDOWS(state, win)
  703.     {
  704.       files_t *file;
  705.       file = WIN_SOURCE(win);
  706.       if ((file != NULL) && (file->type == DTMPORT))
  707.         break;
  708.     }
  709.  
  710.   /* Can't find a window to receive data into. */
  711.   if (win == NULL)
  712.     return;
  713.  
  714.   /* Determine the type of primitive:  points, lines, 
  715.      polygons (n-gons) */
  716.   prim = data->dost;
  717.   strcpy (title, data->label);
  718.  
  719.   path = title;
  720.  
  721.   if (path[0] == '\0')
  722.     /* No title associated with this dataset. */
  723.     /* Default to '/frame0001' */
  724.     strcpy(title, "frame0001");
  725.   else 
  726.     /* Skip the leading slash, if any. */
  727.     if (*path == '/')
  728.       path++;
  729.   
  730.   /* Get a pointer to the vgroup structure that should contain the */
  731.   /* data.  (If the structure does not already exist, create it). */
  732.   /* The vgroup should be the first that matches the name "title" */
  733.   /* within the window's file. */
  734.   if ((vg = set_vgroup(state, WIN_SOURCE(win), path)) == NULL) 
  735.     {
  736.       /* The vgroup does not exist.  Create it. */
  737.       vg = add_vgroup(state, -1, path, WIN_SOURCE(win)->groups);
  738.       reset = TRUE;
  739.     }
  740.   else
  741.     reset = FALSE;
  742.   
  743.   count = ReadVertexList(state, vg, data);
  744.   switch(prim)  
  745.     {
  746.     case SDLpoint:
  747.     case SDLsphere:
  748.       /* Do nothing... we have the vertices. */
  749.       break;
  750.       
  751.     case SDLlineseg:
  752.       BuildConnectList(state, vg, 2, count);
  753.       break;
  754.       
  755.     case SDLtriangle:
  756.       BuildConnectList(state, vg, 3, count);
  757.       break;
  758.       
  759.     case SDLquad:
  760.       BuildConnectList(state, vg, 4, count);
  761.       break;
  762.       
  763.     default:
  764.       stprintf(state, "SYSTEM ERROR: Received unsupported primitive.\n");
  765.       break;
  766.     }
  767.   
  768.   WIN_GROUP(win) = set_vgroup(state, WIN_SOURCE(win), WIN_GROUPNAME(win));
  769.   data_load(state, win, reset);
  770. }
  771.  
  772.  
  773. /* ------------------------------------------------------------------------ */
  774. /* ---------------------------- COMreceive_com ---------------------------- */
  775. /* ------------------------------------------------------------------------ */
  776.  
  777. /* Oh boy, the fun part.
  778.    We receive text commands, prefixed by "polyview". */
  779.  
  780. /* This flag prevents us from rebroadcasting events that we have 
  781.    just received. */
  782. static int last_command_from_dtm = 0;
  783.  
  784. static void COMreceive_com (Com *c, caddr_t state_addr)
  785. {
  786.   char *command;
  787.  
  788.   if (strncmp ("polyview ", c->mesg, 9) == 0)
  789.     {
  790. #ifdef PRIVATE_SUPPORT
  791.       /* Check for privacy enabled. */
  792.       if (gstate->active_windows->private)
  793.         goto done;
  794. #endif
  795.  
  796.       /* Oh boy, it's ours! */
  797.       command = strcpy ((char *)PVMALLOC (strlen(c->mesg)+1), &(c->mesg[9]));
  798.  
  799.       /* Make sure we don't rebroadcast this command. */
  800.       last_command_from_dtm = 1;
  801.  
  802.       /* Go process it.  This will result in a call to COMsend_com,
  803.          which will be bounced right back since last_command_from_dtm
  804.          is high. */
  805.       parse_line ((state_t *)state_addr, command, FALSE);
  806.     }
  807.  
  808.  done:
  809.   return;
  810. }
  811.  
  812.  
  813. void COMsend_com (state_t *state, char *command)
  814. {
  815.   char *mesg;
  816.  
  817.   /* Quietly return if outport not active. */
  818.   if (!done_outport)
  819.     return;
  820.  
  821.   /* If the last command came from DTM, bong. */
  822.   if (last_command_from_dtm)
  823.     {
  824.       last_command_from_dtm = 0;
  825.       return;
  826.     }
  827.  
  828. #ifdef PRIVATE_SUPPORT
  829.   /* If we have privacy turned on, don't send anything. */
  830.   if (state->active_windows->private)
  831.     return;
  832. #endif
  833.  
  834. #if 0
  835.   /* Change moves to jumps to get where we're going quickly. */
  836.   if (strncmp (command, "move camera", 11) == 0)
  837.     {
  838.       /* :-) */
  839.       command[0] = 'j';
  840.       command[1] = 'u';
  841.       command[2] = 'm';
  842.       command[3] = 'p';
  843.     }
  844. #endif
  845.  
  846.   /* Some commands are useless over the net. */
  847.   if (
  848. #ifdef PRIVATE_SUPPORT
  849.       strncmp (command, "dtm private", 11) == 0 ||
  850.       strncmp (command, "dtm public", 10) == 0 ||
  851. #endif
  852.       strncmp (command, "do ", 3) == 0 ||
  853.       strncmp (command, "script", 6) == 0 ||
  854.       strncmp (command, "data file", 9) == 0 ||
  855.       strncmp (command, "data load", 9) == 0 ||
  856.       strncmp (command, "data dtm", 8) == 0 ||
  857.       strncmp (command, "dtm", 3) == 0 ||
  858.       strncmp (command, "blast", 5) == 0 ||
  859.       strncmp (command, "save", 4) == 0
  860.       )
  861.     return;
  862.   
  863.   /* This WILL NOT WORK, since we will not have loaded our own data by
  864.      the time we reach here.  (All we've done is added our 'data load'
  865.      command to our action list.) */
  866. #if 0
  867.   /* If we're loading our own data, send the data across. */
  868.   if (strncmp (command, "data load", 9) == 0)
  869.     {
  870.       window_t *win = state->active_windows;
  871.       if (WIN_GROUP(win) != NULL)
  872.         {
  873.           /* We assume sequential transmissions. */
  874.           COMsend_vset (state, WIN_GROUP(win));
  875.           NetSendCommand 
  876.             (NULL, "Polyview", "polyview data load\0", NULL, NULL);
  877.         }
  878.       return;
  879.     }
  880. #endif
  881.   
  882.   mesg = (char *) PVMALLOC (strlen (command) + 20);
  883.   sprintf (mesg, "polyview %s\0", command);
  884.   NetSendCommand (NULL, "Polyview", mesg, NULL, NULL);
  885.  
  886.   return;
  887. }
  888.  
  889. static void COMreceive_srv (Server *srv, caddr_t state_addr)
  890. {
  891.   if (srv->func == SRV_FUNC_CONNECT)
  892.     done_outport = 1;
  893. }
  894.  
  895. /* ------------------------------------------------------------------------ */
  896. /* ------------------------------ COMdtm_in ------------------------------- */
  897. /* ------------------------------------------------------------------------ */
  898.  
  899. void COMdtm_in (state_t *state, char *path)
  900. {
  901.   NetPort *inport;
  902.   static char userID[200];
  903.   
  904.   if (!done_init)
  905.     {
  906.       char host[65];
  907.  
  908.       if (cuserid(userID) != NULL &&
  909.       gethostname(host, 64) >= 0)
  910.           strcat(strcat(userID, "@"), host);
  911.       else
  912.           gethostname(userID, 64);
  913.  
  914.       NetInit (strcat(userID, " (Polyview 3.1)"));
  915.       done_init = 1;
  916.     }
  917.   
  918.   if (!done_register)
  919.     {
  920.       NetRegisterModule
  921.         ("Polyview", NETVDATA,
  922.          COMreceive_vdata, (caddr_t) state,
  923.          NULL, (caddr_t) 0,
  924.          NULL, (caddr_t) 0);
  925.       NetRegisterModule
  926.         ("Polyview", NETSDL,
  927.          COMreceive_sdl, (caddr_t) state,
  928.          NULL, (caddr_t) 0,
  929.          NULL, (caddr_t) 0);
  930.       NetRegisterModule
  931.         ("Polyview", NETCOM,
  932.          COMreceive_com, (caddr_t) state,
  933.          NULL, (caddr_t) 0,
  934.          NULL, (caddr_t) 0);
  935.       NetRegisterModule
  936.         ("Polyview", NETSRV,
  937.          COMreceive_srv, (caddr_t) state,
  938.          NULL, (caddr_t) 0,
  939.          NULL, (caddr_t) 0);
  940.       done_register = 1;
  941.     }
  942.   
  943.   if (!done_inport)
  944.     {
  945.       inport = NetCreateInPort (path);
  946.       /* Tell the user. */
  947.       stprintf (state, "Created input port.\n");
  948.       done_inport = 1;
  949.     }
  950.   else
  951.     {
  952. #if 0
  953.       fprintf 
  954.         (stdout, "[COMdtm_in] BONNNNNNNG quietly, already have inport\n");
  955.       fflush (stdout);
  956. #endif
  957.     }
  958.   
  959.   return;
  960. }
  961.  
  962.  
  963. /* ------------------------------------------------------------------------ */
  964. /* ------------------------------ COMdtm_out ------------------------------ */
  965. /* ------------------------------------------------------------------------ */
  966.  
  967. /* called from pvtext:do_dtm_out */
  968. int COMdtm_out (state_t *state, window_t *win, char *port)
  969. {
  970.   if (!done_outport)
  971.     {
  972.       /* Get everything set up to support DTM. */
  973.       /* HEY!  This looks bad... we want true two-way communication... */
  974.       COMdtm_in (state, ":0");
  975.       
  976.       /* Make the output port. */
  977.       NetCreateOutPort (port);
  978.  
  979.       done_outport = 1;
  980.     }
  981.   else
  982.     {
  983.       fprintf (stderr, "ERROR trying to make additional outport port.\n");
  984.       fflush (stderr);
  985.     }
  986.   
  987.   return ST_OKAY;
  988. }
  989.  
  990. /* Predicate for outport active. */
  991. int COMdtm_out_active_p (state_t *state)
  992. {
  993.   if (done_outport)
  994.     return 1;
  995.   else
  996.     return 0;
  997. }
  998.  
  999.  
  1000. /* ------------------------------------------------------------------------ */
  1001. /* ------------------------------- COMpoll -------------------------------- */
  1002. /* ------------------------------------------------------------------------ */
  1003.  
  1004. void COMpoll (state_t *state)
  1005. {
  1006.   if (done_inport)
  1007.     NetClientPollAndRead ();
  1008.   
  1009.   return;
  1010. }
  1011.